package conf

import (
	"fmt"
	"os"
	"time"

	"github.com/nsqio/go-nsq"
	"github.com/spf13/viper"
)

// Config 配置
type Config struct {
	Base     *Base       `mapstructure:"base"`
	PgSql    *Postgresql `mapstructure:"postgresql"`
	Redis    *RedisConf  `mapstructure:"redis"`
	HTTP     *HTTP       `mapstructure:"http"`
	NSQConf  *NSQConf    `mapstructure:"nsq"`
	Keys     *Keys       `mapstructure:"keys"`
	RPC      *gRPCConf   `mapstructure:"rpc"`
	Platform *platConf   `mapstructure:"platform"`
	Cos      *Cos        `mapstructure:"cos"`
}

// NSQConf NSQ 配置
type NSQConf struct {
	NSQAddress    string `mapstructure:"nsq_address"`
	LookupAddress string `mapstructure:"lookup_address"`
}

// HTTP 服务端口配置
type HTTP struct {
	Address           string        `mapstructure:"address"`
	ReadTimeout       time.Duration `mapstructure:"read_timeout"`
	WriteTimeout      time.Duration `mapstructure:"write_timeout"`
	ReadHeaderTimeout time.Duration `mapstructure:"read_header_timeout"`
	IdleTimeout       time.Duration `mapstructure:"idle_timeout"`
}

// RPC 服务端口配置
type gRPCConf struct {
	Port       string `mapstructure:"rpc_port"`
	AccountRpc string `mapstructure:"account_rpc"`
	OpenRpc    string `mapstructure:"open_rpc"`
}

// Base 基本信息
type Base struct {
	Name          string `mapstructure:"name"`
	PidFile       string `mapstructure:"pid_file"`
	MaxProc       int
	BugAccount    string `mapstructure:"bug_account"`
	BugAccountPwd string `mapstructure:"bug_account_pwd"`
	Root          string `mapstructure:"root"`
}

// Postgresql pg sql
type Postgresql struct {
	Host         string        `mapstructure:"host"`
	Port         string        `mapstructure:"port"`
	User         string        `mapstructure:"user"`
	Password     string        `mapstructure:"password"`
	Dbname       string        `mapstructure:"dbname"`
	ReadTimeout  time.Duration `mapstructure:"read_timeout"`
	WriteTimeout time.Duration `mapstructure:"write_timeout"`
	IdleTimeout  time.Duration `mapstructure:"idle_timeout"`
	MaxOpenConns int           `mapstructure:"max_open_conns"`
	MaxIdleConns int           `mapstructure:"max_idle_conns"`
	MaxLifeTime  time.Duration `mapstructure:"max_life_time"`
}

// RedisConf is struct of redis config
type RedisConf struct {
	Password    string        `mapstructure:"password"`
	Address     string        `mapstructure:"address"`
	DefaultDB   int           `mapstructure:"default_db"`
	MaxRetries  int           `mapstructure:"max_retries"`
	IdleTimeout time.Duration `mapstructure:"idle_timeout"`
}

type Keys struct {
	JWTPublicKey   string        `mapstructure:"jwt_pub_key"`
	JWTPrivateKey  string        `mapstructure:"jwt_pri_key"`
	TokenDuration  time.Duration `mapstructure:"token_duration"`
	Secret         string        `mapstructure:"secret"`
	QQLbsKey       string        `mapstructure:"qq_lbs_key"`
	QQLbsSecret    string        `mapstructure:"qq_lbs_secret"`
	QiniuAccessKey string        `mapstructure:"qiniu_access_key"`
	QiniuSecretKey string        `mapstructure:"qiniu_secret_key"`
}

// platConf 平台侧配置
type platConf struct {
	// 公众号 appid
	MpAppId string `mapstructure:"mp_app_id"`
}

type Cos struct {
	AppID         string   `mapstructure:"app_id"`
	SecretID      string   `mapstructure:"secret_id"`
	SecretKey     string   `mapstructure:"secret_key"`
	Buckets       []string `mapstructure:"buckets"`
	Regions       []string `mapstructure:"regions"`
	CustomDomains []string `mapstructure:"custom_domains"`
	AllowApps     []string `mapstructure:"allow_apps"`
}

// NewConfig new config
func NewConfig() *Config {
	NSQ := nsq.NewConfig()
	NSQ.MaxInFlight = 5
	NSQ.MsgTimeout = 3 * time.Second
	// 默认设置
	return &Config{
		Base: &Base{
			Name:    "dev",
			PidFile: "/tmp/bilinadmin.pid",
		},
		PgSql: &Postgresql{
			Host:         "",
			Port:         "",
			User:         "",
			Password:     "",
			Dbname:       "bilinadmin",
			ReadTimeout:  60 * time.Second,
			WriteTimeout: 60 * time.Second,
			IdleTimeout:  0,
			MaxOpenConns: 6,
			MaxIdleConns: 2,
			MaxLifeTime:  10 * time.Minute,
		},
		Redis: &RedisConf{
			Password:    "",
			Address:     "",
			DefaultDB:   0,
			MaxRetries:  3,
			IdleTimeout: 5 * time.Second,
		},
		HTTP: &HTTP{
			Address:           "0.0.0.0:8998",
			ReadTimeout:       120 * time.Second,
			WriteTimeout:      120 * time.Second,
			ReadHeaderTimeout: 10 * time.Second,
			IdleTimeout:       10 * time.Second,
		},
		NSQConf: &NSQConf{
			NSQAddress:    "",
			LookupAddress: "",
		},
		RPC: &gRPCConf{
			Port: ":7778",
		},
		Keys: &Keys{
			JWTPublicKey:  "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8vOtJEQmp14qhEeNzV6Dta0ou\nkt+vktu8WU2J1K6MPqYaGwj3ML8Nb4x436j+TLunQgyj5JqJfKJQo7oXi7Yhaq+n\nQ1J39pOKLYm6Le01NWV6fIdccNdOJ0VIoNyBbCBYdkodod/vAYHuStmupehBhoES\nYtowgrQ1hd5B6Rh1MwIDAQAB\n-----END PUBLIC KEY-----",
			JWTPrivateKey: "-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQC8vOtJEQmp14qhEeNzV6Dta0oukt+vktu8WU2J1K6MPqYaGwj3\nML8Nb4x436j+TLunQgyj5JqJfKJQo7oXi7Yhaq+nQ1J39pOKLYm6Le01NWV6fIdc\ncNdOJ0VIoNyBbCBYdkodod/vAYHuStmupehBhoESYtowgrQ1hd5B6Rh1MwIDAQAB\nAoGBALJ7laWLTzAmfRrE5+tzuuPKymQw0QggQVxkt0bYshg+RqX5WwkoOARksNq9\n5/pUZkFN3NZAoUPTcUwBCUKrBJgErfQgqmdVL6lUgWIA+2lrPczVyDvYqYhKixip\nu2NbNOiVQDPz92Ocgr0HYUxif10hjW+U/mImruE83gIVh3JBAkEA61jkyo3kvTy8\nMh0hPIDnQQOZkZ5s3IV0nAb9diti2QAvaUVVTHsUatx9ocqy17s7YHG9e01w/4ET\nUuvHuLVoNwJBAM1M8SMWj1OMRxM0l5yKf226G8oCVzztKFbrRW4WSEiKtwlY8X2Q\nHJA1k4OgGheNrqy1No8hMKNIP+yQeFLppOUCQGlBAmHMf+ZaSVioSnsCs2oSMBY+\nIjWlwfcd8TFuSfD+8jVEetePnBwGrHE1dDKjW/TQKYwBoG3Ezl2hcVscVpUCQHf3\nNhFi5W3U0tOOL+nxpHTiA8sPgxq/Gotv/6pMqwB4zmxP5Q2SYJ6EMCcCLz0ENcYG\nPlN0+Y7wcSozYZxRm2ECQDY/ujOuI0iCB14PCSTywujCAzCIobRgdkiAs9szUxo0\nmPVooyZpW8VIpjTW5fQOujbAyk6lgdASvRpD/dgCL/4=\n-----END RSA PRIVATE KEY-----",
			TokenDuration: 7 * 24 * time.Hour,
			Secret:        "",
		},
		Platform: &platConf{
			MpAppId: "",
		},
		Cos: &Cos{
			AppID:         "",
			SecretID:      "",
			SecretKey:     "",
			Buckets:       []string{},
			Regions:       []string{},
			CustomDomains: []string{},
			AllowApps:     []string{},
		},
	}
}
func overrideConfByEnvVars(config *Config) {
	EnvNsqd, ok := os.LookupEnv("NSQD_ADDRESS")
	if ok && EnvNsqd != "" {
		config.NSQConf.NSQAddress = EnvNsqd
	}
}

// Init is func to initial log config
func Init(configFile string) (*Config, error) {
	cfg := NewConfig()
	viper.SetConfigFile(configFile)
	if err := viper.ReadInConfig(); err != nil {
		return nil, err
	}
	if err := viper.Unmarshal(&cfg); err != nil {
		panic(fmt.Errorf("unable to decode into struct：%s ", err))
	}
	overrideConfByEnvVars(cfg)
	return cfg, nil
}
